﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using LinearAlgebra.MatrixAlgebra;
using LinearAlgebra.VectorAlgebra;

namespace LinearAlgebra
{
    /// <summary>
    /// 非线性函数库
    /// </summary>
    public static class UnlinearFunctionHelper
    {
        #region 缓存函数对象

        private static Dictionary<Type, IFunction> functionPool = new Dictionary<Type, IFunction>();
        /// <summary>
        /// 获取一个被缓存的函数对象
        /// </summary>
        public static IFunction GetFunctionObj<T>() where T : IFunction
        {
            var type = typeof(T);
            if (functionPool.ContainsKey(type)) return functionPool[type];
            var obj = Activator.CreateInstance<T>();
            functionPool.Add(type, obj);
            return obj;
        }
        /// <summary>
        /// 缓存函数对象
        /// </summary>
        /// <param name="func"></param>
        public static void CacheFunctionObj(IFunction func)
        {
            var type = func.GetType();
            if (functionPool.ContainsKey(type))
            {
                functionPool[type] = func;
                return;
            }
            functionPool.Add(type, func);
        }

        #endregion

        public static VectorAlgebra.Vector DoFunction(VectorAlgebra.Vector vector, IFunction func)
        {
            int count = vector.Count;
            VectorAlgebra.Vector result = VectorAlgebra.Vector.Zero(count, vector.vectorType);

            unsafe
            {
                fixed (double* v = vector.Elements)
                fixed (double* r = result.Elements)
                    for (int i = 0; i < count; i++)
                    {
                        r[i] = func.Solve(v[i]);
                    }
            }

            return result;
        }

        public static VectorAlgebra.Vector DoFunction<T>(VectorAlgebra.Vector vector) where T : IFunction
        {
            var funcObj = GetFunctionObj<T>();
            return DoFunction(vector, funcObj);
        }


        public static MatrixAlgebra.Matrix DoFunction(MatrixAlgebra.Matrix matrix, IFunction func)
        {
            int count = matrix.Count;
            MatrixAlgebra.Matrix result = MatrixAlgebra.SpecialMatrices.Ones(matrix.RowCount, matrix.ColumnCount);

            unsafe
            {
                fixed (double* v = matrix.Elements)
                fixed (double* r = result.Elements)
                    for (int i = 0; i < count; i++)
                    {
                        r[i] = func.Solve(v[i]);
                    }
            }

            return result;
        }
        public static MatrixAlgebra.Matrix DoFunction<T>(MatrixAlgebra.Matrix matrix) where T : IFunction
        {
            var funcObj = GetFunctionObj<T>();
            return DoFunction(matrix, funcObj);
        }

        #region 特殊非线性函数的定义
        public interface IFunction
        {
            /// <summary>
            /// 导函数
            /// </summary>
            IFunction Derivative { get; }
            /// <summary>
            /// 开始 x->y 的映射
            /// </summary>
            /// <param name="inps">自变量，根据具体函数，要求的自变量数量也不同</param>
            double Solve(params double[] inps);

            Vector Solve(Vector x);
            Matrix Solve(Matrix x);

            void SetArgs(params string[] args);

        }

        public abstract class FunctionBase : IFunction
        {
            /// <summary>
            /// 导函数
            /// </summary>
            public abstract IFunction Derivative { get; }

            public abstract double Solve(params double[] inps);

            public virtual Vector Solve(Vector x)
            {
                return DoFunction(x, this);
            }

            public virtual Matrix Solve(Matrix x)
            {
                return DoFunction(x, this);
            }

            public virtual void SetArgs(params string[] args) { }
        }

        public class ZeroFunc : FunctionBase
        {
            public override IFunction Derivative { get { return this; } }

            public override double Solve(params double[] inps)
            {
                return 0;
            }
        }
        /// <summary>
        /// 常函数
        /// </summary>
        public class ConstFunc : FunctionBase
        {
            public override IFunction Derivative { get { return GetFunctionObj<ZeroFunc>(); } }

            public double ConstVal;

            public ConstFunc(double constVal)
            {
                ConstVal = constVal;
            }

            /// <param name="inps"></param>
            public override double Solve(params double[] inps)
            {
                return ConstVal;
            }
        }

        /// <summary>
        /// 分段常函数
        /// </summary>
        public class PiecewiseConstFunc : FunctionBase
        {
            public override IFunction Derivative { get { return GetFunctionObj<ZeroFunc>(); } }

            public double[] XPos;
            public double[] YPos;

            /// <param name="xPos">分界点</param>
            /// <param name="yPos">各段的y常量</param>
            public PiecewiseConstFunc(double[] xPos, double[] yPos)
            {
                Array.Sort(xPos);
                XPos = xPos;
                YPos = yPos;
            }

            public override double Solve(params double[] inps)
            {
                if (inps == null || inps.Length < 1) throw new ArgumentException("参数应为一个doubel");

                int index;
                for (index = 0; index < XPos.Length; index++)
                {
                    if (inps[0] < XPos[index])
                    {
                        break;
                    }
                }

                if (index < 0) index = 0;
                else if (index > YPos.Length - 1) index = YPos.Length - 1;

                return YPos[index];
            }
        }

        /// <summary>
        /// 分段函数
        /// </summary>
        public class PiecewiseFunc : FunctionBase
        {
            public override IFunction Derivative { get { return GetFunctionObj<ZeroFunc>(); } }

            public double[] XPos;
            public IFunction[] YPos;

            /// <param name="xPos">分界点</param>
            /// <param name="yPos">各段的函数</param>
            public PiecewiseFunc(double[] xPos, IFunction[] yPos)
            {
                Array.Sort(xPos);
                XPos = xPos;
                YPos = yPos;
            }

            public override double Solve(params double[] inps)
            {
                if (inps == null || inps.Length < 1) throw new ArgumentException("参数应为一个doubel");

                int index = -1;
                for (int i = 0; i < XPos.Length; i++)
                {
                    if (inps[0] < XPos[i])
                    {
                        index = i;
                        break;
                    }
                }

                if (index < 0) index = 0;
                else if (index > YPos.Length - 1) index = YPos.Length - 1;

                return YPos[index].Solve(inps[0]);
            }
        }

        /// <summary>
        /// 逻辑斯蒂函数<br/>
        /// y = 1/(1+e^-x)<br/>
        /// 定义域：R<br/>
        /// 值域：(0,1)
        /// </summary>
        public class Sigmoid_01 : FunctionBase
        {
            public override IFunction Derivative
            {
                get
                {
                    if (derivative == null)
                    {
                        derivative = GetFunctionObj<Sigmoid_Derivative>();
                    }
                    return derivative;
                }
            }
            private IFunction derivative;

            /// <param name="inps">一个double</param>
            public override double Solve(params double[] inps)
            {
                if (inps == null || inps.Length < 1) throw new ArgumentException("参数应为一个doubel");

                return 1 / (1 + Math.Exp(-inps[0]));
            }

        }

        /// <summary>
        /// 逻辑斯蒂函数<br/>
        /// y = 2((1/(1+e^-x))-0.5)<br/>
        /// 定义域：R<br/>
        /// 值域：(-1,1)
        /// </summary>
        public class Sigmoid_n11 : FunctionBase
        {
            public override IFunction Derivative
            {
                get
                {
                    return sigmoid.Derivative;// 因为只是对Sigmoid做了平移，不改变其导函数
                }
            }
            private Sigmoid_01 sigmoid;
            public Sigmoid_n11()
            {
                sigmoid = new Sigmoid_01();
            }

            /// <param name="inps">一个double</param>
            public override double Solve(params double[] inps)
            {
                return 2 * (sigmoid.Solve(inps[0]) - 0.5);
            }
        }

        /// <summary>
        /// 逻辑斯蒂函数的导函数
        /// </summary>
        public class Sigmoid_Derivative : FunctionBase
        {
            public override IFunction Derivative
            {
                get { throw new NotImplementedException(); }
            }
            private Sigmoid_01 sigmoid;
            public Sigmoid_Derivative()
            {
                sigmoid = new Sigmoid_01();
            }

            /// <param name="inps">一个double</param>
            public override double Solve(params double[] inps)
            {
                var temp = sigmoid.Solve(inps[0]);
                return temp * (1 - temp);
            }

        }


        /// <summary>
        /// 线性整流函数<br/>
        /// y = max(0,x)
        /// </summary>
        public class ReLU : FunctionBase
        {
            public override IFunction Derivative
            {
                get
                {
                    if (derivative == null)
                    {
                        derivative = GetFunctionObj<ReLU_Derivative>();
                    }
                    return derivative;
                }
            }
            private IFunction derivative;

            public override double Solve(params double[] inps)
            {
                if (inps == null || inps.Length < 1) throw new ArgumentException("参数应为一个doubel");

                return Math.Max(0, inps[0]);
            }

        }

        /// <summary>
        /// 线性整流函数的导函数<br/>
        /// y = 0(x<=0) | 1(x>0)
        /// </summary>
        public class ReLU_Derivative : FunctionBase
        {
            public override IFunction Derivative { get { return GetFunctionObj<ZeroFunc>(); } }
            public override double Solve(params double[] inps)
            {
                if (inps == null || inps.Length < 1) throw new ArgumentException("参数应为一个doubel");

                return inps[0] > 0 ? 1 : 0;
            }
        }

        /// <summary>
        /// 线性整流函数<br/>
        /// y = ax(x<=0) | bx(x>0)
        /// </summary>
        public class ReLU_AB : FunctionBase
        {
            public override IFunction Derivative
            {
                get
                {
                    return new PiecewiseConstFunc(new double[] { 0 }, new double[] { A, B });
                }
            }

            public double A { get; set; }
            public double B { get; set; }
            public ReLU_AB(double a, double b)
            {
                A = a;
                B = b;
            }

            public override double Solve(params double[] inps)
            {
                if (inps == null || inps.Length < 1) throw new ArgumentException("参数应为一个doubel");

                double k = inps[0] <= 0 ? A : B;

                return k * inps[0];
            }
        }

        public class Lieaner : FunctionBase
        {
            public override IFunction Derivative { get; }

            public Lieaner()
            {
                Derivative = new ConstFunc(1);
            }

            public override double Solve(params double[] inps)
            {
                return inps[0];
            }
        }
        #endregion
    }
}
